home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mntlb20 / lib / stat.c < prev    next >
C/C++ Source or Header  |  1991-11-06  |  8KB  |  309 lines

  1. /*
  2.  * stat, fstat, lstat emulation for TOS
  3.  * written by Eric R. Smith and placed in the public domain
  4.  */
  5.  
  6. #include <limits.h>
  7. #include <types.h>
  8. #include <stat.h>
  9. #include <ctype.h>
  10. #include <errno.h>
  11. #include <osbind.h>
  12. #include <mintbind.h>
  13. #include <string.h>
  14. #include <time.h>
  15. #include <unistd.h>
  16. #include <ioctl.h>    /* for FSTAT */
  17. #include "lib.h"
  18.  
  19. extern int __mint;
  20.  
  21. ino_t    __inode = 32;        /* used in readdir also */
  22.  
  23. /* for backwards compatibilty: if nonzero, files are checked to see if
  24.  * they have the TOS executable magic number in them
  25.  */
  26.  
  27. int    _x_Bit_set_in_stat = 0;
  28.  
  29.  
  30.  
  31. /* date for files (like root directories) that don't have one */
  32. #define OLDDATE _unixtime(0,0)
  33.  
  34. /*
  35.  * macro for converting a long in DOS format to one in Unix format. "x"
  36.  * _must_ be an lvalue!
  37.  */
  38.  
  39. #define CONVERT(x) (x = _unixtime( ((short *)&x)[0], ((short *)&x)[1] ))
  40.  
  41. /*
  42.  * common routine for stat() and lstat(); if "lflag" is 0, then symbolic
  43.  * links are automatically followed (like stat), if 1 then they are not
  44.  * (like lstat)
  45.  */
  46.  
  47. static int
  48. do_stat(_path, st, lflag)
  49.     const char *_path;
  50.     struct stat *st;
  51.     int lflag;
  52. {
  53.     long    r, olddta;
  54.     int    nval;
  55.     char    path[PATH_MAX];
  56.     char    *ext, drv;
  57.     int    fd;
  58.     short    magic;
  59.     _DTA    d;
  60.     int    isdot = 0;
  61.  
  62.     if (!_path) {
  63.         errno = EFAULT;
  64.         return -1;
  65.     }
  66.  
  67. /*
  68.  * _unx2dos returns 1 for device names (like /dev/con)
  69.  */
  70.     nval = _unx2dos(_path, path);
  71.  
  72. /* for MiNT 0.9 and up, we use the built in stat() call */
  73.     if (__mint >= 9) {
  74.         r = Fxattr(lflag, path, st);
  75.         if (r) {
  76.             errno = -r;
  77.             return -1;
  78.         }
  79.         CONVERT(st->st_mtime);
  80.         CONVERT(st->st_atime);
  81.         CONVERT(st->st_ctime);
  82.     /* Most versions of Unix count in 512 byte blocks */
  83.         st->st_blocks = (st->st_blocks * st->st_blksize) / 512;
  84.         return 0;
  85.     }
  86.  
  87. /* otherwise, check to see if we have a name like CON: or AUX: */
  88.     if (nval == 1) {
  89.         st->st_mode = S_IFCHR | 0600;
  90.         st->st_attr = 0;
  91.         st->st_ino = ++__inode;
  92.         st->st_rdev = 0;
  93.         st->st_mtime = st->st_ctime = st->st_atime = 
  94.             time((time_t *)0) - 2;
  95.         st->st_dev = 0;
  96.         st->st_nlink = 1;
  97.         st->st_uid = geteuid();
  98.         st->st_gid = getegid();
  99.         st->st_size = st->st_blocks = 0;
  100.         st->st_blksize = 1024;
  101.         return 0;
  102.     }
  103.  
  104. /* A file name: check for root directory of a drive */
  105.     if (path[0] == '\\' && path[1] == 0) {
  106.         drv = Dgetdrv() + 'A';
  107.         goto rootdir;
  108.     }
  109.  
  110.     if ( (drv = path[0]) && path[1] == ':' &&
  111.          (path[2] == 0 || (path[2] == '\\' && path[3] == 0)) ) {
  112. rootdir:
  113.         st->st_mode = S_IFDIR | 0755;
  114.         st->st_attr = FA_DIR;
  115.         st->st_dev = isupper(drv) ? drv - 'A' : drv - 'a';
  116.         st->st_ino = 2;
  117.         st->st_mtime = st->st_ctime = st->st_atime = OLDDATE;
  118.         goto fill_dir;
  119.     }
  120.  
  121. /* forbid wildcards in path names */
  122.     if (index(path, '*') || index(path, '?')) {
  123.         errno = ENOENT;
  124.         return -1;
  125.     }
  126.  
  127. /* OK, here we're going to have to do an Fsfirst to get the date */
  128. /* NOTE: Fsfirst(".",-1) or Fsfirst("..",-1) both fail under TOS,
  129.  * so we kludge around this by using the fact that Fsfirst(".\*.*"
  130.  * or "..\*.*" will return the correct file first (except, of course,
  131.  * in root directories :-( ).
  132.  */
  133.  
  134. /* find the end of the string */
  135.     for (ext = path; ext[0] && ext[1]; ext++) ;
  136.  
  137. /* add appropriate kludge if necessary */
  138.     if (*ext == '.' && (ext == path || ext[-1] == '\\' || ext[-1] == '.')) {
  139.         isdot = 1;
  140.         strcat(path, "\\*.*");
  141.     }
  142.     olddta = Fgetdta();
  143.     Fsetdta(&d);
  144.     r = Fsfirst(path, 0xff);
  145.     Fsetdta(olddta);
  146.     if (r < 0) {
  147.         if (isdot && r == -ENOENT) goto rootdir;
  148.         errno = -r;
  149.         return -1;
  150.     }    
  151.  
  152.     if (isdot && ((d.dta_name[0] != '.') || (d.dta_name[1]))) {
  153.         goto rootdir;
  154.     }
  155.  
  156.     st->st_mtime = st->st_ctime = st->st_atime =
  157.         _unixtime(d.dta_time, d.dta_date);
  158.     if ((drv = *path) && path[1] == ':')
  159.         st->st_dev = toupper(drv) - 'A';
  160.     else
  161.         st->st_dev = Dgetdrv();
  162.  
  163.     st->st_ino = __inode++;
  164.     st->st_attr = d.dta_attribute;
  165.     if (__mint && st->st_dev == ('Q' - 'A'))
  166.             st->st_mode = 0644 | S_IFIFO;
  167.     else {
  168.         st->st_mode = 0644 | (st->st_attr & FA_DIR ?
  169.                   S_IFDIR | 0111 : S_IFREG);
  170.     }
  171.  
  172.     if (st->st_attr & FA_RDONLY)
  173.         st->st_mode &= ~0222;    /* no write permission */
  174.     if (st->st_attr & FA_HIDDEN)
  175.         st->st_mode &= ~0444;    /* no read permission */
  176.  
  177. /* check for a file with an executable extension */
  178.     ext = strrchr(_path, '.');
  179.     if (ext) {
  180.         if (!strcmp(ext, ".ttp") || !strcmp(ext, ".prg") ||
  181.             !strcmp(ext, ".tos") || !strcmp(ext, ".g") ||
  182.             !strcmp(ext, ".sh")     || !strcmp(ext, ".bat")) {
  183.             st->st_mode |= 0111;
  184.         }
  185.     }
  186.     if ( (st->st_mode & S_IFMT) == S_IFREG) {
  187.         if (_x_Bit_set_in_stat) {
  188.             if ((fd = Fopen(path,0)) < 0) {
  189.                 errno = -fd;
  190.                 return -1;
  191.             }
  192.             magic = 0;
  193.             (void)Fread(fd,2,(char *)&magic);
  194.             (void)Fclose(fd);
  195.             if (magic == 0x601A    /* TOS executable */
  196.                 || magic == 0x2321) /* "#!" shell file */
  197.                 st->st_mode |= 0111;
  198.         }
  199.         st->st_size = d.dta_size;
  200.     /* in Unix, blocks are measured in 512 bytes */
  201.         st->st_blocks = (st->st_size + 511) / 512;
  202.         st->st_nlink = 1; /* we dont have hard links */
  203.     } else {
  204. fill_dir:
  205.         st->st_size = 1024;
  206.         st->st_blocks = 2;
  207.         st->st_nlink = 2;    /* "foo" && "foo/.." */
  208.     }
  209.  
  210.     st->st_rdev = 0;
  211.     st->st_uid = geteuid();    /* the current user owns every file */
  212.     st->st_gid = getegid();
  213.     st->st_blksize = 1024;
  214.     return 0;
  215. }
  216.  
  217.  
  218. /* 
  219.  * fstat: if we're not running under MiNT, this is pretty bogus.
  220.  * what we can really find is:
  221.  * modification time: via Fdatime()
  222.  * file size: via Fseek()
  223.  * fortunately, these are the things most programs are interested in.
  224.  * BUG: passing an invalid file descriptor gets back a stat structure for
  225.  * a tty.
  226.  */
  227.  
  228. int
  229. fstat(fd, st)
  230. int fd;
  231. struct stat *st;
  232. {
  233.     long oldplace, r;
  234.     short timeptr[2];
  235.     short magic;
  236.  
  237.     if (__mint >= 9) {        /* use FSTAT Fcntl */
  238.         r = Fcntl(fd, st, (long)FSTAT);
  239.         if (r) {
  240.             errno = -r;
  241.             return -1;
  242.         }
  243.         CONVERT(st->st_mtime);
  244.         CONVERT(st->st_atime);
  245.         CONVERT(st->st_ctime);
  246.         st->st_blocks = (st->st_blocks * st->st_blksize) / 512;
  247.         return 0;
  248.     }
  249.  
  250.     r = Fdatime(timeptr, fd, 0);
  251.     if (r < 0) {            /* assume TTY */
  252.         st->st_mode = S_IFCHR | 0600;
  253.         st->st_attr = 0;
  254.         st->st_mtime = st->st_ctime = st->st_atime =
  255.             time((time_t *)0) - 2;
  256.         st->st_size = 0;
  257.     } else {
  258.         st->st_mtime = st->st_atime = st->st_ctime =
  259.             _unixtime(timeptr[0], timeptr[1]);
  260.         st->st_mode = S_IFREG | 0644;        /* this may be false */
  261.         st->st_attr = 0;            /* because this is */
  262.  
  263.     /* get current file location */
  264.         oldplace = Fseek(0L, fd, SEEK_CUR);
  265.         if (oldplace < 0) {        /* can't seek -- must be pipe */
  266.             st->st_mode = S_IFIFO | 0644;
  267.             st->st_size = 1024;
  268.         } else {
  269.             r = Fseek(0L, fd, SEEK_END);    /* go to end of file */
  270.             st->st_size = r;
  271.             (void)Fseek(0L, fd, SEEK_SET);    /* go to start of file */
  272.             /* check for executable file */
  273.             if (Fread(fd, 2, (char *)&magic) == 2) {
  274.                 if (magic == 0x601a || magic == 0x2321)
  275.                     st->st_mode |= 0111;
  276.             }
  277.             (void)Fseek(oldplace, fd, SEEK_SET);
  278.         }
  279.     }
  280.  
  281. /* all this stuff is likely bogus as well. sigh. */
  282.     st->st_dev = Dgetdrv();
  283.     st->st_rdev = 0;
  284.     st->st_uid = getuid();
  285.     st->st_gid = getgid();
  286.     st->st_blksize = 1024;
  287. /* note: most Unixes measure st_blocks in 512 byte units */
  288.     st->st_blocks = (st->st_size + 511) / 512;
  289.     st->st_ino = ++__inode;
  290.     st->st_nlink = 1;
  291.     return 0;
  292. }
  293.  
  294. int
  295. lstat(path, st)
  296.     const char *path;
  297.     struct stat *st;
  298. {
  299.     return do_stat(path, st, 1);
  300. }
  301.  
  302. int
  303. stat(path, st)
  304.     const char *path;
  305.     struct stat *st;
  306. {
  307.     return do_stat(path, st, 0);
  308. }
  309.